package com.gmail.hh.flickrj.sample.android.data;

import java.util.ArrayList;
import java.util.Date;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import android.graphics.PointF;
import android.util.FloatMath;
import android.view.MotionEvent;

import com.googlecode.flickrjandroid.photos.Photo;
import com.googlecode.flickrjandroid.photos.PhotoList;


/**
 * a Wrapper for Photo and ImageView --- 
 * 
 * @author helmut
 * 
 */
public class PhotolistData  { 
	
	private static final Logger logger = LoggerFactory.getLogger(PhotolistData.class);
	

	// each Class which uses the zoomFaktor must implement this interface
	public interface IPhotolistZoomChanged {
		public void onZoomFactorChangedAfterMoved(float zoomFactor);
		public void onZoomFactorChangedAfterFinished(float zoomFactor);
	}

	public static final String MOVEDIRECTION_BACKWARD = "BACKWARD";
	public static final String MOVEDIRECTION_FORWARD = "FORWARD";
	
	private ArrayList<PhotoData> photoDatas;
	private static final float SCALE_DEFAULT = 1.0f;
	private static final float ZOOMFACTOR_LOWERLIMIT = 0.2f;
	private static final float ZOOMFACTOR_UPPERLIMIT = 5.0f;
	private float photoListZoomFactor = SCALE_DEFAULT;  // default originial Size
	private static final int NONE = 0;
	private static final int DRAG = 1;
	private static final int ZOOM = 2;
	private int mode = NONE;
	private PointF mid = new PointF();
	private float oldDist = 1f;
	private float scale;
	private boolean scaleChanged;
	private long startTime;
	private static final long MSEC_DELAY_FIREMOVED = 500; //msec delay default
	private long versionCounter = 0;
	
	
	// constructor 
	public PhotolistData() {
		super();
	}


	public void putPhotolist(PhotoList photolist){
		photoDatas = null;
		if (photolist!=null) {
			photoDatas = new ArrayList<PhotoData>();
			for (int i=0; i<photolist.size(); i++ ) {
				Photo photo = photolist.get(i);
				PhotoData photoData = new PhotoData();
				photoData.setPhoto(photo);
				photoDatas.add(photoData);
			}
		}
		versionCounter = new Date().getTime();
	}	
	
	public void deletePhotoDatas(){
		photoDatas = null;
		versionCounter = new Date().getTime();
	}	
	
	public void addPhotoData(PhotoData photoData){
		photoDatas = null;
		if (photoData!=null) {
			if (photoDatas==null) {
				photoDatas = new ArrayList<PhotoData>();
			}
			photoDatas.add(photoData);
		}
		versionCounter = new Date().getTime();
	}

	public int size( ){
		int size = 0;
		if (photoDatas!=null) {
			size = photoDatas.size();
		}
		return size;
	}

	public PhotoData getAtPosition(int position ){
		PhotoData photoData = null;
		if (photoDatas!=null) {
			if (position >=0 && position<size() ) {
				photoData = photoDatas.get(position);
			}
		}
		return photoData;
	}
	

	public boolean applyTouchEvent( IPhotolistZoomChanged callbackPhotolistZoomChanged, MotionEvent event,
								Long msec_delay_fireMoved) {
		    // Handle touch events here...
		    switch (event.getAction() & MotionEvent.ACTION_MASK) {
		    case MotionEvent.ACTION_DOWN:
		        mode = DRAG;
		        break;
		    case MotionEvent.ACTION_POINTER_DOWN:
		        oldDist = spacing(event);
		        if (oldDist > 10f) {
		            midPoint(mid, event);
			        mode = ZOOM;
		            scale = SCALE_DEFAULT;
		            scaleChanged = false;
		            startTime = new Date().getTime();
		        }
		        break;
		    case MotionEvent.ACTION_UP:
		    case MotionEvent.ACTION_POINTER_UP:
		        mode = NONE;
		    	if (scaleChanged) {
		    		scaleChanged=false;
		            logger.error("PointerUP: new Zoom-Factor: " + photoListZoomFactor);
		    		callbackPhotolistZoomChanged.onZoomFactorChangedAfterFinished(this.photoListZoomFactor);
		        }
		        break;
		    case MotionEvent.ACTION_MOVE:
		        if (mode == DRAG) {
		            // ...
		        } else if (mode == ZOOM) {
		            float newDist = spacing(event);
		            if (newDist > 10f) {
		                scale = newDist / oldDist;
				    	if (scale!= SCALE_DEFAULT ) {
				    		float zoomFactor = photoListZoomFactor * scale;
				    		photoListZoomFactor = checkZoomFactorLimits(zoomFactor);
				    		oldDist = newDist; // reset Distance 
				    		scaleChanged = true;
				            long timeEnd = new Date().getTime();
					    	if (msec_delay_fireMoved==null ) {  // more than 500 msec
					    		msec_delay_fireMoved = Long.valueOf(MSEC_DELAY_FIREMOVED);
					     	}
			            	if (timeEnd-startTime > msec_delay_fireMoved.longValue()  ) {  // more than xxx msec
					            logger.error("Move-fired with ZoomFactor: " + photoListZoomFactor);
					    		startTime = timeEnd; // resetTime
					    		callbackPhotolistZoomChanged.onZoomFactorChangedAfterMoved(this.photoListZoomFactor);
			            	}
		            	}
		            }
		        }
	        break;
		    }
		return true;  	// stop propagation true/false
	    				// when return false, then its possible that move/zoom is failing
	}
	
	/** Determine the space between the first two fingers */
	private float spacing(MotionEvent event) {
		float spacingValue=0;
	    try {
			float x = event.getX(0) - event.getX(1);
			float y = event.getY(0) - event.getY(1);
			spacingValue = FloatMath.sqrt(x * x + y * y);
		} catch (IllegalArgumentException e) {
            logger.error("spacing: IllegalArgumentException"  + e.toString() );
		}
	    return spacingValue;
	}

	/** Calculate the mid point of the first two fingers */
	private void midPoint(PointF point, MotionEvent event) {
		float midPointValue=0;
	    try {
		    float x = event.getX(0) + event.getX(1);
		    float y = event.getY(0) + event.getY(1);
		    point.set(x / 2, y / 2);
		} catch (IllegalArgumentException e) {
            logger.error("midPoint: IllegalArgumentException"  + e.toString() );
		}
	}


	
	public float checkZoomFactorLimits(float zoomFactor) {
		float zoomFactorLimited = zoomFactor;
		if (zoomFactorLimited < ZOOMFACTOR_LOWERLIMIT ) {
			zoomFactorLimited = ZOOMFACTOR_LOWERLIMIT;
		}
		if (zoomFactorLimited > ZOOMFACTOR_UPPERLIMIT ) {
			zoomFactorLimited = ZOOMFACTOR_UPPERLIMIT;
		}
		return zoomFactorLimited;
	}
	

    // movement in Photolist-Collection
    public int moveInPhotolist(String moveDirection, int actualPosition) {
    	int nextPosition = actualPosition;
    	if (moveDirection == MOVEDIRECTION_FORWARD)  {
    	    nextPosition++;
        } 
    	if (moveDirection == MOVEDIRECTION_BACKWARD)  {
    	    nextPosition--;
        } 
    	if (nextPosition<0 || nextPosition>=this.size() )  {
    		nextPosition = actualPosition;  // no movement
        } 
    	return nextPosition;
    }
	
	
	// check two PhotolistData if the both have the same version counter  
	public boolean isEqualVersionCounter(PhotolistData photolistData2) {
		boolean isEqual = false;
		if (photolistData2!=null && this.versionCounter==photolistData2.versionCounter) {
			isEqual = true;
		}
		return isEqual;
	}
	
	// getter settter
	public float getPhotolistZoomFactor() {
		return photoListZoomFactor;
	}
	

}
